﻿Friend Class RescanQueue

    Private Shared mRescanQueue As New Generic.List(Of QueueItem)

    Public Class QueueItem
        Public DeadLine As Date
        Public Share As Entities.SharedWatchFolder
        Public StartPath As String
        Public RetryCount As Integer

        Friend Function GetStartsInAsText() As String
            Dim tsStartsIn As TimeSpan = DeadLine.Subtract(Now)
            If tsStartsIn.TotalSeconds < 1 Then
                Return "as soon as possible"
            Else
                Return String.Format(" as soon as possible after {0} seconds", CInt(tsStartsIn.TotalSeconds))
            End If
        End Function
    End Class

    Public Shared Sub Queue(ByVal share As Entities.SharedWatchFolder, ByVal startPath As String, ByVal delay As TimeSpan)
        Dim clsItem As New QueueItem
        clsItem.Share = share
        clsItem.StartPath = startPath.ToLower
        clsItem.DeadLine = Now.Add(delay)
        Queue(clsItem)
    End Sub
    Public Shared Sub ReQueue(ByVal item As QueueItem)
        item.RetryCount += 1
        item.DeadLine = Now.AddSeconds(30)
        Queue(item)
    End Sub

    Private Shared Sub Queue(ByVal item As QueueItem)
        SyncLock mRescanQueue
            Dim clsExistingItem As QueueItem = Nothing
            Select Case GetPathQueueStatus(item.StartPath, clsExistingItem)
                Case PathQueueStatus.NotQueued
                    mRescanQueue.Add(item)
                    Manager.OnLogEvent(String.Format("Rescan of ""{0}"" queued to start in {1} s", item.StartPath, item.GetStartsInAsText))
                Case PathQueueStatus.Queued
                    clsExistingItem.DeadLine = item.DeadLine
                    clsExistingItem.RetryCount = item.RetryCount
                    Manager.OnLogEvent(String.Format("Rescan of ""{0}"" deadline changed to start in {1} s", clsExistingItem.StartPath, clsExistingItem.GetStartsInAsText))
                Case PathQueueStatus.IsParentToQueued
                    For i As Integer = mRescanQueue.Count - 1 To 0 Step -1
                        Dim clsItem As QueueItem = mRescanQueue(i)
                        If Utils.IO.IsSubDir(clsItem.StartPath, item.StartPath) Then
                            mRescanQueue.RemoveAt(i)
                            Manager.OnLogEvent(String.Format("Rescan of ""{0}"" removed from queue", clsItem.StartPath))
                        End If
                    Next
                    mRescanQueue.Add(item)
                    Manager.OnLogEvent(String.Format("Rescan of ""{0}"" queued to start in {1} s", item.StartPath, item.GetStartsInAsText))
                Case PathQueueStatus.ParentIsQueued
                    clsExistingItem.DeadLine = item.DeadLine
                    clsExistingItem.RetryCount = item.RetryCount
                    Manager.OnLogEvent(String.Format("Rescan of ""{0}"" is included in queued scan for parent ""{1}"" and will start in {2} s", item.StartPath, clsExistingItem.StartPath, clsExistingItem.GetStartsInAsText))
            End Select
        End SyncLock
    End Sub
    Public Shared Function GetNextItemToScan() As QueueItem
        Dim dtClosest As Date = Date.MaxValue
        Dim clsSelected As QueueItem = Nothing
        SyncLock mRescanQueue
            For Each clsItem As QueueItem In mRescanQueue
                If clsItem.DeadLine < dtClosest And clsItem.DeadLine < Now Then
                    dtClosest = clsItem.DeadLine
                    clsSelected = clsItem
                End If
            Next
            If clsSelected IsNot Nothing Then mRescanQueue.Remove(clsSelected)
        End SyncLock
        Return clsSelected
    End Function

    Private Enum PathQueueStatus
        NotQueued
        ParentIsQueued
        IsParentToQueued
        Queued
    End Enum

    Private Shared Function GetPathQueueStatus(ByVal startPath As String, ByRef ret_Item As QueueItem) As PathQueueStatus
        For Each clsItem As QueueItem In mRescanQueue
            If clsItem.StartPath = startPath Then
                ret_Item = clsItem
                Return PathQueueStatus.Queued
            ElseIf Utils.IO.IsSubDir(clsItem.StartPath, startPath) Then
                ret_Item = clsItem
                Return PathQueueStatus.IsParentToQueued
            ElseIf Utils.IO.IsSubDir(startPath, clsItem.StartPath) Then
                ret_Item = clsItem
                Return PathQueueStatus.ParentIsQueued
            End If
        Next
        ret_Item = Nothing
        Return PathQueueStatus.NotQueued
    End Function
End Class
